package com.boarsoft.boar.oss.service.impl;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectRequest;
import com.boarsoft.bean.ReplyInfo;
import com.boarsoft.boar.oss.service.BoarOssClient;
import com.boarsoft.boar.oss.util.OSSUtil;
import com.boarsoft.boar.oss.consts.CommonConst;
import com.boarsoft.common.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.List;

/**
 * @author tao.wang57
 * @desc 基于阿里云OSS的服务实现
 * @date 2023-03-22 pm
 */
public class AliyunOssServiceImpl implements BoarOssClient {

    private static final Logger log = LoggerFactory.getLogger(AliyunOssServiceImpl.class);
    private String bucketName;
    @Autowired
    private Environment environment;

    private OSS getOssClient(String tenantNo) {
        if (StringUtil.isBlank(tenantNo)) {
            log.error("tenantNo 不允许为空");
        }

        String ak = environment.getProperty(tenantNo.concat(CommonConst.OSS_AK_SUFFIX));
        if (StringUtil.isBlank(ak)) {
            log.error("租户：{}下没有配置对应的 accessKeyId ", tenantNo);
        }

        String sk = environment.getProperty(tenantNo.concat(CommonConst.OSS_SK_SUFFIX));
        if (StringUtil.isBlank(sk)) {
            log.error("租户：{}下没有配置对应的 accessKeySecret ", tenantNo);
        }

        String endpoint = environment.getProperty(tenantNo.concat(CommonConst.OSS_ENDPOINT_SUFFIX));
        if (StringUtil.isBlank(endpoint)) {
            log.error("租户：{}下没有配置对应的 endpoint ", tenantNo);
        }

        String bucketName = environment.getProperty(tenantNo.concat(CommonConst.OSS_BUCKETNAME_SUFFIX));
        this.bucketName = bucketName;
        if (StringUtil.isBlank(bucketName)) {
            log.error("租户：{}下没有配置对应的 bucketName ", tenantNo);
        }

        return new OSSClientBuilder().build(endpoint, ak, sk);
    }

    @Override
    public ReplyInfo<Object> downloadFile(String tenantNo, String fileName, String localFolder, String remoteFolder) {
        if (localFolder == null || remoteFolder == null) {
            return ReplyInfo.error("本地目录或OSS目录不能为空");
        }
        File file = new File(localFolder);
        if (!file.exists()) {
            file.mkdirs();
        }
        if (!file.isDirectory()) {
            return ReplyInfo.error(localFolder + "不是一个正确的目录");
        }
        OSS ossClient = getOssClient(tenantNo);
        try {
            String remoteFilePath = format(remoteFolder) + "/" + fileName;
            String localFilePath = format(localFolder) + "/" + fileName;
            ossClient.getObject(new GetObjectRequest(bucketName, remoteFilePath), new File(localFilePath));
        } catch (OSSException | ClientException e) {
            log.error("下载文件时发生异常:", e);
            throw e;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return ReplyInfo.SUCCESS;
    }

    @Override
    public InputStream download(String tenantNo, String objectName) {
        InputStream input = null;
        OSS ossClient = getOssClient(tenantNo);
        try{
            //ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流
            OSSObject ossObject = ossClient.getObject(bucketName, objectName);
            input = ossObject.getObjectContent();
        } catch (Exception e) {
            log.error("下载文件时发生异常:", e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return input;
    }

    @Override
    public ReplyInfo<Object> uploadFile(String tenantNo, InputStream inputStream, String fileName, String remoteFolder) {
        if (remoteFolder == null) {
            return ReplyInfo.error("OSS目录不能为空");
        }
        String remoteFilePath = format(remoteFolder) + "/" + fileName;
        OSS ossClient = getOssClient(tenantNo);
        try {
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, remoteFilePath, inputStream);
            ossClient.putObject(putObjectRequest);
        } catch (OSSException | ClientException e) {
            log.error("文件上传异常:", e);
            throw e;
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return ReplyInfo.SUCCESS;
    }

    @Override
    public ReplyInfo<Object> uploadFile(String tenantNo, String fileName, String localFolder, String remoteFolder) {
        if (localFolder == null || remoteFolder == null) {
            return ReplyInfo.error("本地目录或OSS目录不能为空");
        }
        String localFilePath = format(localFolder) + "/" + fileName;
        File file = new File(localFilePath);
        if (!file.exists()) {
            return ReplyInfo.error(localFilePath + "文件不存在");
        }
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            log.error("文件上传异常：", e);
        }
        this.uploadFile(tenantNo, inputStream, fileName, remoteFolder);
        return ReplyInfo.SUCCESS;
    }

    @Override
    public ReplyInfo<Object> deleteFile(String tenantNo, String key) {
        OSSUtil.deleteFile(getOssClient(tenantNo), bucketName, key);
        return ReplyInfo.SUCCESS;
    }

    @Override
    public ReplyInfo<Object> list(String tenantNo, String bucketName) {
        ReplyInfo<Object> result = new ReplyInfo<Object>();
        List<String> list = OSSUtil.queryAllObject(getOssClient(tenantNo), bucketName);
        result.setData(list);
        result.setSuccess(Boolean.TRUE);
        return result;
    }

    private String format(String folder) {
        if (folder.endsWith("/")) {
            return folder.substring(0, folder.length() - 1);
        } else if (folder.endsWith("\\")) {
            return folder.substring(0, folder.length() - 2);
        } else {
            return folder;
        }
    }
}
